from datetime import datetime
import uuid
from typing import Any, List

from app.tests.utils import user
from sqlmodel import Session, func, select

from app.core.security import get_password_hash, verify_password
from app.models import Device, Item, ItemCreate, Project, Record, SpeechData, User, UserCreate, UserUpdate, ZentaoData


def create_user(*, session: Session, user_create: UserCreate) -> User:
    db_obj = User.model_validate(
        user_create, update={"hashed_password": get_password_hash(user_create.password)}
    )
    session.add(db_obj)
    session.commit()
    session.refresh(db_obj)
    return db_obj


def update_user(*, session: Session, db_user: User, user_in: UserUpdate) -> Any:
    user_data = user_in.model_dump(exclude_unset=True)
    extra_data = {}
    if "password" in user_data:
        password = user_data["password"]
        hashed_password = get_password_hash(password)
        extra_data["hashed_password"] = hashed_password
    db_user.sqlmodel_update(user_data, update=extra_data)
    session.add(db_user)
    session.commit()
    session.refresh(db_user)
    return db_user


def get_user_by_email(*, session: Session, email: str) -> User | None:
    statement = select(User).where(User.email == email)
    session_user = session.exec(statement).first()
    return session_user


def authenticate(*, session: Session, email: str, password: str) -> User | None:
    db_user = get_user_by_email(session=session, email=email)
    if not db_user:
        return None
    if not verify_password(password, db_user.hashed_password):
        return None
    return db_user


def create_item(*, session: Session, item_in: ItemCreate, owner_id: uuid.UUID) -> Item:
    db_item = Item.model_validate(item_in, update={"owner_id": owner_id})
    session.add(db_item)
    session.commit()
    session.refresh(db_item)
    return db_item

def get_device_by_mac(session: Session, mac: str) -> Device | None:
    statement = select(Device).where(Device.mac == mac)
    device = session.exec(statement).first()
    return device

def create_device(session: Session, device:Device) -> Device:
    session.add(device)
    session.commit()
    return device

def update_device(session: Session, device:Device) -> Device:
    session.add(device)
    session.commit()
    return device

def create_speech_data(session: Session, data: SpeechData) -> None:
    session.add(data)
    session.commit()
    return data

def update_speech_data(session: Session, data: SpeechData) -> None:
    session.add(data)
    session.commit()
    return data

def create_zentao_data(session: Session, data: ZentaoData) -> None:
    session.add(data)
    session.commit()
    return data

def get_zentao_data_by_date(session: Session, date: datetime) -> List[ZentaoData]:
    statement = select(ZentaoData).where(func.date(ZentaoData.create_time) == date.date())
    zentao_data = session.exec(statement).all()
    return zentao_data

def get_speech_data_by_speech_id(session: Session, speech_id: str) -> SpeechData | None:
    statement = select(SpeechData).where(SpeechData.task_id == speech_id)
    speech_data = session.exec(statement).first()
    return speech_data

def get_speech_data_by_date(session: Session, date: datetime) -> List[SpeechData]:
    statement = select(SpeechData).where(func.date(SpeechData.create_time) == date.date())
    speech_data = session.exec(statement).all()
    return speech_data

def get_devices(session: Session) -> List[Device]:
    statement = select(Device)
    devices = session.exec(statement).all()
    return devices

def get_devices_by_user_id(session: Session, user_id: int) -> List[Device]:
    statement = select(Device).where(Device.user_id == user_id) 
    devices = session.exec(statement).all()
    return devices

def get_record_by_script_hash(session: Session, script_hash: str) -> Record | None:
    statement = select(Record).where(Record.script_hash == script_hash)
    record = session.exec(statement).first()
    return record

def create_project(session: Session, name:str) -> Project:
    db_project = Project(name=name)
    session.add(db_project)
    session.commit()
    session.refresh(db_project)
    return db_project

def get_project_by_name(session: Session, name: str) -> Project | None:
    statement = select(Project).where(Project.name == name)
    project = session.exec(statement).first()
    return project

def get_projects(session: Session) -> List[Project]:
    statement = select(Project)
    projects = session.exec(statement).all()
    return projects